package com.example.demo.datasource;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;
import com.example.demo.domain.ProjectConfig;
import com.example.demo.exception.BaseException;
import com.example.demo.util.FileUtil;
import com.example.demo.util.JsonUtil;
import com.fasterxml.jackson.databind.ser.Serializers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;

public class DataSourceUtil {

    private static final Logger logger = LoggerFactory.getLogger(DataSourceUtil.class);

    private static String projectPath = FileUtil.projectPath;

    private static String sepa = FileUtil.getSystemSeparator();

    public static void setDB(String dbName) throws BaseException {
        //如果数据源在连接池中不存在，则创建数据源并添加到连接池中
        if (!DynamicDataSource.isExistDataSource(dbName)) {
            //从配置文件中读取数据源信息
            String fileName = projectPath + sepa + "query_config" + sepa + dbName + sepa +
                    "ProjectConfig.json";

            ProjectConfig projectConfig = JsonUtil.readObjectFromFile(fileName, ProjectConfig.class);
            //创建数据源
            DruidDataSource dynamicDataSource = druidDataSource(projectConfig);
            //把数据源添加到连接池中
            Map<Object, Object> map = DynamicDataSource.getInstance().getDataSourceMap();
            map.put(dbName, dynamicDataSource);
            DynamicDataSource.getInstance().setTargetDataSources(map);
        }
        //切换数据源
        DataSourceContextHolder.setDBType(dbName);
    }

    public static void clearDb() {
        DataSourceContextHolder.clearDBType();
    }

    //从map中移除指定连接池
    public static void removeDB(String dbName) {
        Map<Object, Object> map = DynamicDataSource.getInstance().getDataSourceMap();
        map.remove(dbName);
        DynamicDataSource.getInstance().setTargetDataSources(map);
    }

    //根据配置生成连接池
    private static DruidDataSource druidDataSource(ProjectConfig projectConfig) {

        DruidDataSource dataSource = new DruidDataSource();
        //jdbc设置
        dataSource.setDriverClassName(projectConfig.getDriverClassName());
        dataSource.setUrl(projectConfig.getUrl());
        dataSource.setUsername(projectConfig.getUsername());
        dataSource.setPassword(projectConfig.getPassword());
        //连接池设置
        dataSource.setMaxActive(projectConfig.getMaxActive());
        dataSource.setMinIdle(projectConfig.getMinIdle());
        dataSource.setInitialSize(projectConfig.getInitialSize());
        dataSource.setMaxWait(projectConfig.getMaxWait());
        dataSource.setTimeBetweenEvictionRunsMillis(projectConfig.getTimeBetweenEvictionRunsMillis());
        dataSource.setMinEvictableIdleTimeMillis(projectConfig.getMinEvictableIdleTimeMillis());
        dataSource.setTestWhileIdle(projectConfig.getTestWhileIdle());
        dataSource.setTestOnBorrow(projectConfig.getTestOnBorrow());
        dataSource.setTestOnReturn(projectConfig.getTestOnReturn());
        dataSource.setValidationQuery(projectConfig.getValidationQuery());

        dataSource.setPoolPreparedStatements(projectConfig.getPoolPreparedStatements());
        dataSource.setMaxPoolPreparedStatementPerConnectionSize(projectConfig.getMaxPoolPreparedStatementPerConnectionSize());

        try {
            DruidPooledConnection con = dataSource.getConnection();
        } catch (SQLException e) {
            dataSource.close();
            String msg = e.getMessage();
            if (msg.toUpperCase().contains("ORA-01017")) {
                throw new BaseException(500, "用户名或密码错误，请联系管理员！");
            }
            if (msg.toUpperCase().contains("The Network Adapter could not establish the connection".toUpperCase()) ||
                    msg.toUpperCase().contains("ORA-12514")) {
                throw new BaseException(500, "连接数据库失败，请联系管理员，检查参数是否正确！");
            }
            if (msg.toUpperCase().contains("ORA-00028")) {
                throw new BaseException(500, "用户被锁定，请联系管理员！");
            }
            throw new BaseException(e);
        }
        return dataSource;
    }
}
